package com.bracketbird.client.model;


import com.bracketbird.client.model.tournament.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class CupScheduler extends Scheduler<CupRound> {

    private static char[] charNames = new char[]{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','X','Y','Z'};

    private List<CupRound> allRounds = new ArrayList<CupRound>();
    private List<PlayingTeam> playingTeams;
    private TournamentLevel level;
    private int matchNumber = 1;

    public CupScheduler(List<PlayingTeam> playingTeams, TournamentLevel level) {
        this.playingTeams = playingTeams;
        this.level = level;
        build();
    }

    private void build() {
        //return the number of teams nessecary to fill cup at the specifik round
        int binaryTeamCount = getBinaryTeamCount();


        List<PlayingTeam> bTeamList = createTeamList(binaryTeamCount);


        List<Match> left = new ArrayList<Match>();
        List<Match> right = new ArrayList<Match>();


        left.add(createMatch(bTeamList, 1));
        List<Match> pointer = right;
        int count = 0;
        while (!bTeamList.isEmpty()){
            if(count == 2){
                count = 0;
                pointer = pointer == right ? left : right;
            }
            pointer.add(createMatch(bTeamList, 1));
            count++;
        }

        Collections.reverse(right);
        List<Match> allMatchesFirstRound = new ArrayList<Match>();
        allMatchesFirstRound.addAll(left);
        allMatchesFirstRound.addAll(right);
        addNames(allMatchesFirstRound, 0);

        CupRound firstRound = new CupRound(allMatchesFirstRound);

        List<CupRound> rounds = new ArrayList<CupRound>();
        rounds.add(firstRound);

        int roundNumber = 2;
        CupRound tempRound = firstRound;
        while (tempRound.size() > 1){
            tempRound = buildNextRound(tempRound, roundNumber++);
            rounds.add(tempRound);
        }

        allRounds = rounds;
    }

    private void addNames(List<Match> allMatchesFirstRound, int charNameIndex) {
        char c = charNames[charNameIndex];
        int i = 1;
        for (Match m : allMatchesFirstRound) {
            m.setName((""+c)+i++);
        }
    }

    private CupRound buildNextRound(CupRound previousRound, int roundNumber) {
        List<Match> list = new ArrayList<Match>();
        char c = charNames[(int)roundNumber];
        int nameIndex = 1;
        int count = 0;
        while (count < previousRound.size()){
            Match one = previousRound.get(count++);
            Match two = previousRound.get(count++);
            Match m = MatchFac.create(level, null, roundNumber, matchNumber++);
            m.setTeamHome(new SeedingTeam(one.getName()));
            m.setTeamOut(new SeedingTeam(two.getName()));
            m.setName((""+c)+nameIndex++);
            list.add(m);
        }
        return new CupRound(list);

    }

    private Match createMatch(List<PlayingTeam> list, long roundNumber){
        Match m = MatchFac.create(level, null, roundNumber, matchNumber++);
        m.setTeamHome(list.remove(0));
        m.setTeamOut(list.remove(list.size()-1));
        return m;
    }


    private List<PlayingTeam> createTeamList(int binaryTeamCount){
        List<PlayingTeam> list = new ArrayList<PlayingTeam>();
        for (PlayingTeam pt : playingTeams) {
            list.add(pt);
        }

        int walkOvers = binaryTeamCount - playingTeams.size();
        while(walkOvers > 0){
            list.add(new WalkOverTeam("---"));
            walkOvers--;
        }
        return list;
    }

    private int getBinaryTeamCount() {
        int binaryCount = 1;
        while (playingTeams.size() > binaryCount) {
            binaryCount = binaryCount * 2;
        }
        return binaryCount;
    }


    @Override
    public List<CupRound> getRounds() {
        return allRounds;
    }


}
